/*
 * Copyright (c) 2010-2013 Ruben Chakhmakhchyan. All rights reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Eclipse Public License
 * Version 1.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/EPL-1.0 and read it before using this file.
 */

#include "scripting_utils.h"
#include "strings.h"
#include "list.h"
#include "scripting.h"


char* ScriptingUtils::npstring( const char* s )
{
    return String::Clone( s, ::NPN_MemAlloc );
}

char* ScriptingUtils::npstring( const wchar_t* s )
{
    char* result = NULL;

    String::ToUtf8( &result, s, ::NPN_MemAlloc, ::NPN_MemFree );

    return result;
}

wchar_t* ScriptingUtils::npstringToWchar( const NPString* npstring )
{
    return String::Utf8ToWideChar( npstring->UTF8Characters, npstring->UTF8Length );
}

wchar_t* ScriptingUtils::npstringToWchar( const NPUTF8* chars, uint32_t length )
{
    return String::Utf8ToWideChar( chars, length );
}

bool ScriptingUtils::npoToArray( NPP npp, NPObject* npo, ArrayType type, void** a )
{
    int length = 0;

    NPVariant npvResult, npvNameProperty, npvLengthProperty;
    VOID_TO_NPVARIANT( npvResult );
    VOID_TO_NPVARIANT( npvNameProperty );
    VOID_TO_NPVARIANT( npvLengthProperty );

    NPIdentifier constructorId = npid.constructor; //NPN_GetStringIdentifier( "constructor" );
    NPIdentifier nameId = npid.name; //NPN_GetStringIdentifier( "name" );
    NPIdentifier lengthId = npid.length; //NPN_GetStringIdentifier( "length" );
    bool isArray = false;

    if ( ::NPN_HasProperty( npp, npo, constructorId ) )
    {
        if ( ::NPN_GetProperty( npp, npo, constructorId, &npvResult ) )
        {
            if ( ::NPN_GetProperty( npp, NPVARIANT_TO_OBJECT( npvResult ), nameId, &npvNameProperty ) )
            {
                isArray = NPVARIANT_IS_STRING( npvNameProperty );
            }
        }
    }

    if ( isArray )
    {
        if ( ::NPN_GetProperty( npp, npo, lengthId, &npvLengthProperty ) )
        {
            if ( IS_NUMERIC( npvLengthProperty ) )
            {
                length = AS_INT( npvLengthProperty );

                if ( length > 0 )
                {
                    List<int>* pIntArray = NULL;
                    List<char*>* pUtf8Array = NULL;
                    List<wchar_t*>* pUtf16Array = NULL;
                    bool arrayFilled = true;

                    //*( ( int* ) a ) = type == ArrayTypeInt ? ( int ) ( intArray = new int[ length ] ) : ( int ) ( stringArray = new char*[ length ] );
                    switch ( type )
                    {
                    case ArrayType::Int: *a = pIntArray = new List<int>( length ); break;
                    case ArrayType::StringUtf8: *a = pUtf8Array = new List<char*>( length ); break;
                    case ArrayType::StringUtf16: *a = pUtf16Array = new List<wchar_t*>( length ); break;
                    }

                    List<int>& intArray = *pIntArray;
                    List<char*>& utf8Array = *pUtf8Array;
                    List<wchar_t*>& utf16Array = *pUtf16Array;

                    int i = 0;
                    for ( ; i < length; i++ )
                    {
                        NPVariant npvIndex, npvArrayElementValue;
                        INT32_TO_NPVARIANT( i, npvIndex );

                        if ( ::NPN_GetProperty( npp, npo, ::NPN_GetIntIdentifier( i ), &npvArrayElementValue ) )
                        {
                            if ( type == ArrayType::Int )
                            {
                                if ( NPVARIANT_IS_INT32( npvArrayElementValue ) )
                                {
                                    intArray.add( NPVARIANT_TO_INT32( npvArrayElementValue ) );
                                }
                                else
                                {
                                    // cleanup
                                    break;
                                }
                            }
                            else
                            {
                                if ( NPVARIANT_IS_STRING( npvArrayElementValue ) )
                                {
                                    NPString s = NPVARIANT_TO_STRING( npvArrayElementValue );
                                    if ( type == ArrayType::StringUtf8 )
                                    {
                                        char* utf8chars = NULL;
                                        String::Copy( &utf8chars, s.UTF8Characters );
                                        utf8Array.add( utf8chars );
                                    }
                                    else
                                    {
                                        utf16Array.add( ScriptingUtils::npstringToWchar( &s ) );
                                    }
                                }
                                else
                                {
                                    // cleanup
                                    break;
                                }
                            }
                        }
                    }

                    if ( i == length )
                    {
                        return true;
                    }
                }
            }
        }
    }

    return false;
}
